package com.aiti.lulian.workflow;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
import com.baomidou.mybatisplus.annotation.TableField;
import java.util.Date;



@TableName("dj_process_definition")
public class ProcessDefinition {
    @TableId(value = "id",type = IdType.UUID)
    private String id;

    private String name;
    private int version;


    private String definitionJson;

    private Date deployedAt;
    private Boolean isActive;

    @TableField(exist = false)
    @JsonIgnore
    private List<Node> nodes;

    @Data
    public static class JsonFormat {
        private String id;
        private String name;
        private Integer version;
        private List<Node> nodes;
    }

    public ProcessDefinition() {
        this.nodes = new ArrayList<>();
        this.isActive = true;
        this.deployedAt = new Date();
    }

    public ProcessDefinition(String id, String name, int version, String definitionJson) {
        this();
        this.id = id;
        this.name = name;
        this.version = version;
        this.definitionJson = definitionJson;
        parseDefinitionJson();
    }

    @JsonIgnore
    public List<Node> getNodes() {
        if (nodes == null || nodes.isEmpty()) {
            parseDefinitionJson();
        }
        return nodes;
    }

    public void setNodes(List<Node> nodes) {
        this.nodes = nodes;
        serializeNodesToJson();
    }



    private void parseDefinitionJson() {
        if (definitionJson == null || definitionJson.trim().isEmpty()) {
            this.nodes = new ArrayList<>();
            return;
        }
        try {
            ObjectMapper mapper = new ObjectMapper();
            JsonFormat jsonFormat = mapper.readValue(definitionJson, JsonFormat.class);
            this.nodes = jsonFormat.nodes != null ? jsonFormat.nodes : new ArrayList<>();
        } catch (Exception e) {
            throw new RuntimeException("Failed to parse process definition JSON", e);
        }
    }


    private void serializeNodesToJson() {
        try {
            ObjectMapper mapper = new ObjectMapper();
            JsonFormat jsonFormat = new JsonFormat();
            jsonFormat.id = this.id;
            jsonFormat.name = this.name;
            jsonFormat.version = this.version;
            jsonFormat.nodes = this.nodes;

            this.definitionJson = mapper.writeValueAsString(jsonFormat);
        } catch (Exception e) {
            throw new RuntimeException("Failed to serialize nodes to JSON", e);
        }
    }

    public Node getNode(String nodeId) {
        return getNodes().stream()
                .filter(node -> node.getId().equals(nodeId))
                .findFirst()
                .orElse(null);
    }

    public Node getStartNode() {
        return getNodes().stream()
                .filter(node -> "startEvent".equals(node.getType()))
                .findFirst()
                .orElseGet(() -> getNodes().stream()
                        .filter(node -> "userTask".equals(node.getType()))
                        .findFirst()
                        .orElse(null));
    }


    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public int getVersion() { return version; }
    public void setVersion(int version) { this.version = version; }

    public String getDefinitionJson() { return definitionJson; }
    public void setDefinitionJson(String definitionJson) {
        this.definitionJson = definitionJson;
        parseDefinitionJson();
    }

    public Date getDeployedAt() { return deployedAt; }
    public void setDeployedAt(Date deployedAt) { this.deployedAt = deployedAt; }

    public Boolean getIsActive() { return isActive; }
    public void setIsActive(Boolean isActive) { this.isActive = isActive; }


}
